package config

import (
	_ "embed"
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/goccy/go-yaml"
	"github.com/spf13/viper"
	"go.uber.org/zap/zapcore"
	"log"
	"os"
)

// 系统配置，对应yml
// viper内置了mapstructure, yml文件用"-"区分单词, 转为驼峰方便
var (
	//go:embed env.yml
	envConfigBytes []byte
	//go:embed localConfig.yml
	localConfigBytes []byte
	//go:embed devConfig.yml
	devConfigBytes []byte
	//go:embed proConfig.yml
	proConfigBytes []byte
	//go:embed gin-mini-admin-priv.pem
	priv []byte
	//go:embed gin-mini-admin-pub.pem
	pub []byte
	// Conf 全局配置变量
	Conf = new(config)
)

type config struct {
	System    *SystemConfig    `mapstructure:"system" json:"system"`
	Logs      *LogsConfig      `mapstructure:"logs" json:"logs"`
	Mysql     *MysqlConfig     `mapstructure:"mysql" json:"mysql"`
	Casbin    *CasbinConfig    `mapstructure:"casbin" json:"casbin"`
	Jwt       *JwtConfig       `mapstructure:"jwt" json:"jwt"`
	RateLimit *RateLimitConfig `mapstructure:"rate-limit" json:"rateLimit"`
}

// InitConfig 设置读取配置信息
func InitConfig() {
	var env EnvConfig

	workDir, err := os.Getwd()
	if err != nil {
		panic(fmt.Errorf("读取应用目录失败:%s \n", err))
	}
	//err = os.Chdir("./config")
	//if err != nil {
	//	log.Printf("Change to config dir failed ")
	//}
	// 添加调试日志
	log.Printf("Current working directory: %s", getCurrentDir())
	log.Printf("Loading env.yml...")

	// 解析 env.yml
	if err = yaml.Unmarshal(envConfigBytes, &env); err != nil {
		log.Printf("Failed to unmarshal env.yml: %v", err)
	}

	log.Printf("Environment name from env.yml: %s", env.EnvName)

	// 根据 env_name 选择配置文件
	if env.EnvName == "pro" {
		// 解析 env.yml
		//if err := yaml.Unmarshal(proConfigBytes, &Conf); err != nil {
		//	log.Printf("Failed to unmarshal env.yml: %v", err)
		//}
		viper.SetConfigName("proConfig")
	} else if env.EnvName == "dev" {
		//if err := yaml.Unmarshal(devConfigBytes, &Conf); err != nil {
		//	log.Printf("Failed to unmarshal env.yml: %v", err)
		//}
		viper.SetConfigName("devConfig")
	} else if env.EnvName == "local" {
		//if err := yaml.Unmarshal(localConfigBytes, &Conf); err != nil {
		//	log.Printf("Failed to unmarshal env.yml: %v", err)
		//}
		viper.SetConfigName("localConfig")
	} else {
		//if err := yaml.Unmarshal(localConfigBytes, &Conf); err != nil {
		//	log.Printf("Failed to unmarshal env.yml: %v", err)
		//}
		viper.SetConfigName("localConfig")
	}

	viper.SetConfigType("yml")
	viper.AddConfigPath(workDir + "./config")
	// 读取配置信息
	err = viper.ReadInConfig()

	// 热更新配置
	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		// 将读取的配置信息保存至全局变量Conf
		if err = viper.Unmarshal(Conf); err != nil {
			panic(fmt.Errorf("初始化配置文件失败:%s \n", err))
		}
		// 读取rsa key
		Conf.System.RSAPublicBytes = pub
		Conf.System.RSAPrivateBytes = priv
	})

	if err != nil {
		panic(fmt.Errorf("读取配置文件失败:%s \n", err))
	}
	// 将读取的配置信息保存至全局变量Conf
	if err = viper.Unmarshal(Conf); err != nil {
		panic(fmt.Errorf("初始化配置文件失败:%s \n", err))
	}
	// 读取rsa key
	Conf.System.RSAPublicBytes = pub
	Conf.System.RSAPrivateBytes = priv

}

type EnvConfig struct {
	EnvName string `yaml:"env-name" json:"EnvName"`
}

type SystemConfig struct {
	Mode            string `mapstructure:"mode" json:"mode"`
	UrlPathPrefix   string `mapstructure:"url-path-prefix" json:"urlPathPrefix"`
	Port            int    `mapstructure:"port" json:"port"`
	InitData        bool   `mapstructure:"init-data" json:"initData"`
	RSAPublicKey    string `mapstructure:"rsa-public-key" json:"rsaPublicKey"`
	RSAPrivateKey   string `mapstructure:"rsa-private-key" json:"rsaPrivateKey"`
	RSAPublicBytes  []byte `mapstructure:"-" json:"-"`
	RSAPrivateBytes []byte `mapstructure:"-" json:"-"`
}

type LogsConfig struct {
	Level      zapcore.Level `mapstructure:"level" json:"level"`
	Path       string        `mapstructure:"path" json:"path"`
	MaxSize    int           `mapstructure:"max-size" json:"maxSize"`
	MaxBackups int           `mapstructure:"max-backups" json:"maxBackups"`
	MaxAge     int           `mapstructure:"max-age" json:"maxAge"`
	Compress   bool          `mapstructure:"compress" json:"compress"`
}

type MysqlConfig struct {
	Username    string `mapstructure:"username" json:"username"`
	Password    string `mapstructure:"password" json:"password"`
	Database    string `mapstructure:"database" json:"database"`
	Host        string `mapstructure:"host" json:"host"`
	Port        int    `mapstructure:"port" json:"port"`
	Query       string `mapstructure:"query" json:"query"`
	LogMode     bool   `mapstructure:"log-mode" json:"logMode"`
	TablePrefix string `mapstructure:"table-prefix" json:"tablePrefix"`
	Charset     string `mapstructure:"charset" json:"charset"`
	Collation   string `mapstructure:"collation" json:"collation"`
}

type CasbinConfig struct {
	ModelPath string `mapstructure:"model-path" json:"modelPath"`
}

type JwtConfig struct {
	Realm      string `mapstructure:"realm" json:"realm"`
	Key        string `mapstructure:"key" json:"key"`
	Timeout    int    `mapstructure:"timeout" json:"timeout"`
	MaxRefresh int    `mapstructure:"max-refresh" json:"maxRefresh"`
}

type RateLimitConfig struct {
	FillInterval int64 `mapstructure:"fill-interval" json:"fillInterval"`
	Capacity     int64 `mapstructure:"capacity" json:"capacity"`
}

func getCurrentDir() string {
	dir, err := os.Getwd()
	if err != nil {
		log.Printf("Error getting current directory: %v", err)
		return "unknown"
	}
	return dir
}
